<template>
  <div class="tool-box">
    <div
      class="tool-box-item"
      :class="{ active: activeMenuId === item.id }"
      v-for="item in menus"
      :key="item.id"
      @click="handleMenuItemClick(item)"
    >
      <SvgIcon :icon-class="item.icon" />
      <span class="name">{{ item.name }}</span>
    </div>
  </div>
</template>

<script setup>
import mapboxgl from 'mapbox-gl'
import {
  length as turfLength,
  area as turfArea,
  center as turfCenter,
} from '@turf/turf'
import { last } from 'lodash'
import SvgIcon from '@/components/svg-icon'
import Vue, { onBeforeMount, onBeforeUnmount, ref } from 'vue'
import { getHelper } from '@/utils/map/index'
import emitter from '@/utils/event-bus'
import MeasurePopup from './MeasurePopup.vue'
import sharedDrawingManager from '@/utils/map/shared-drawing-manager.js'

const _map = new Map()

const _drawControl = new Map()

const _measureResultMarkers = new Map()
const _markerPopupInfos = new Map()

const props = defineProps({
  mapId: {
    type: String,
    required: true,
  },
})

const menus = [
  {
    id: 'measure-length',
    name: '测距离',
    icon: 'measure-length',
  },
  {
    id: 'measure-area',
    name: '测面积',
    icon: 'measure-area',
  },
  {
    id: 'clear',
    name: '清除',
    icon: 'clear',
  },
]

const activeMenuId = ref('')

onBeforeMount(async () => {
  const helper = await getHelper(props.mapId)

  if (helper) {
    // 使用共享的绘制管理器
    const drawControl = sharedDrawingManager.init(helper.map)

    _drawControl.set(props.mapId, drawControl)
    _map.set(props.mapId, helper.map)

    // 使用共享管理器的事件监听
    sharedDrawingManager.addEventListener('draw.create', drawCreateEvent)
    sharedDrawingManager.addEventListener('draw.update', drawUpdateEvent)
    sharedDrawingManager.addEventListener('draw.selectionchange', drawSelectionChangeEvent)
  }
})

onBeforeUnmount(() => {
  if (_map.get(props.mapId)) {
    // 移除共享管理器的事件监听
    sharedDrawingManager.removeEventListener('draw.create', drawCreateEvent)
    sharedDrawingManager.removeEventListener('draw.update', drawUpdateEvent)
    sharedDrawingManager.removeEventListener('draw.selectionchange', drawSelectionChangeEvent)
    removeAllMeasureResultMarkers()
  }
})

/**
 * 绘制结束事件
 *
 * @param {MapboxDraw.DrawCreateEvent} event 绘制事件
 */
const drawCreateEvent = (event) => {
  if (activeMenuId.value === 'measure-length') {
    activeMenuId.value = ''

    const geojson = event.features[0]
    const length = turfLength(geojson, { units: 'kilometers' }).toFixed(2) // 千米
    addMeasureResultMarker(
      geojson.id.toString(),
      length,
      '千米',
      last(geojson.geometry.coordinates)
    )

    _drawControl.get(props.mapId).changeMode('simple_select')
    emitter.emit('MEASURE_ACTIVATE', false)
  } else if (activeMenuId.value === 'measure-area') {
    activeMenuId.value = ''

    const geojson = event.features[0]
    const area = (turfArea(geojson) / 1000 / 1000).toFixed(2) // 平方千米
    addMeasureResultMarker(
      geojson.id.toString(),
      area,
      '平方千米',
      turfCenter(geojson.geometry).geometry.coordinates
    )

    _drawControl.get(props.mapId).changeMode('simple_select')
    emitter.emit('MEASURE_ACTIVATE', false)
  }
}

/**
 * 绘制更新事件
 *
 * @param {MapboxDraw.DrawUpdateEvent} event 绘制更新事件
 */
const drawUpdateEvent = (event) => {
  const geojson = event.features[0]
  let result = ''
  let unit = ''
  let lngLat
  switch (geojson.geometry.type) {
    case 'LineString':
      result = turfLength(geojson, { units: 'kilometers' }).toFixed(2)
      unit = '千米'
      lngLat = last(geojson.geometry.coordinates)
      updateMeasureResultMarker(geojson.id.toString(), result, unit, lngLat)
      break
    case 'Polygon':
      result = (turfArea(geojson) / 1000 / 1000).toFixed(2)
      unit = '平方千米'
      lngLat = turfCenter(geojson.geometry).geometry.coordinates
      updateMeasureResultMarker(geojson.id.toString(), result, unit, lngLat)
      break
    default:
      break
  }
}

/**
 * 绘制选中改变事件
 *
 * @param {MapboxDraw.DrawSelectionChangeEvent} event 绘制选中改变事件
 */
const drawSelectionChangeEvent = (event) => {
  emitter.emit('MEASURE_ACTIVATE', event.features.length > 0)
}

/**
 * 添加测量结果显示marker
 *
 * @param {string} id marker id
 *
 * @param {string} result 测量结果
 *
 * @param {string} unit 测量单位
 *
 * @param {mapboxgl.LngLatLike} lngLat 显示坐标
 */
const addMeasureResultMarker = (id, result, unit, lngLat) => {
  const popupResult = ref(result)
  const popupUnit = ref(unit)
  // const div = getPopupHtml(popupResult, popupUnit);
  const div = document.createElement('div')
  div.style.padding = '3px 5px'
  div.style.backgroundColor = 'rgba(0,0,0,0.5)'
  div.style.borderRadius = '3px'
  const span = document.createElement('span')
  span.style.color = 'white'
  span.style.fontSize = '16px'
  div.appendChild(span)
  span.innerText = `${result}${unit}`
  _markerPopupInfos.set(id.toString(), {
    result: popupResult,
    unit: popupUnit,
  })
  _measureResultMarkers.set(
    id.toString(),
    new mapboxgl.Marker({
      element: div,
      anchor: 'bottom',
      offset: [0, -10],
    })
      .setLngLat(lngLat)
      .addTo(_map.get(props.mapId))
  )
}

const getPopupHtml = (result, unit) => {
  const template = Vue.extend(MeasurePopup, {
    result,
    unit,
  })
  const div = document.createElement('div')
  template.mount(div)
  return div
}

/**
 * 更新测量结果显示marker
 *
 * @param {string} id marker id
 *
 * @param {string} result 测量结果
 *
 * @param {string} unit 测量单位
 *
 * @param {mapboxgl.LngLatLike} lngLat 显示坐标
 */
const updateMeasureResultMarker = (id, result, unit, lngLat) => {
  const marker = _measureResultMarkers.get(id.toString())
  const markerInfos = _markerPopupInfos.get(id.toString())
  if (marker) {
    markerInfos.result.value = result
    markerInfos.unit.value = unit
    marker.getElement().children[0].innerHTML = `${result}${unit}`
    marker.setLngLat(lngLat)
  } else {
    console.error(`未找到id为${id}的marker`)
  }
}

const handleMenuItemClick = (item) => {
  if (item.id === 'clear') {
    activeMenuId.value = ''
    removeAllMeasureResultMarkers()
    _drawControl.get(props.mapId).deleteAll().changeMode('simple_select')
    emitter.emit('MEASURE_ACTIVATE', false)
  } else {
    if (activeMenuId.value === item.id) {
      activeMenuId.value = ''

      _drawControl.get(props.mapId).changeMode('simple_select')
      emitter.emit('MEASURE_ACTIVATE', false)
    } else {
      activeMenuId.value = item.id

      switch (item.id) {
        case 'measure-length':
          _drawControl.get(props.mapId).changeMode('draw_line_string')
          emitter.emit('MEASURE_ACTIVATE', true)
          break
        case 'measure-area':
          _drawControl.get(props.mapId).changeMode('draw_polygon')
          emitter.emit('MEASURE_ACTIVATE', true)
          break
        default:
          break
      }
    }
  }
}

/**
 * 移除所有测量结果marker
 */
const removeAllMeasureResultMarkers = () => {
  _measureResultMarkers.forEach((marker) => {
    marker.remove()
  })
  _markerPopupInfos.clear()
  _measureResultMarkers.clear()
}
</script>

<style lang="scss" scoped>
.tool-box {
  $primary-color: #006fff;
  align-items: center;
  display: flex;
  flex-direction: column;

  width: 55px;
  padding: 10px 0;

  &-item {
    display: flex;
    flex-direction: column;
    align-items: center;

    cursor: pointer;

    &:not(:first-of-type) {
      margin-top: 14px;
    }

    &:hover {
      .svg-icon {
        color: $primary-color;
      }

      span.name {
        color: $primary-color;
      }
    }

    &.active {
      .svg-icon {
        color: $primary-color;
      }

      span.name {
        color: $primary-color;
      }
    }

    .svg-icon {
      width: 20px;
      height: 20px;
      color: black;
    }

    span.name {
      margin-top: 6px;
      font-size: 14px;
      line-height: 14px;
      color: black;
      transition: color 0.3s linear;
    }
  }
}
</style>
